package com.ogilvy.audi.service.impl;

import com.ogilvy.audi.model.util.PageParameter;
import com.ogilvy.audi.util.PageConstants;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.ogilvy.audi.dao.GenericDao;
import com.ogilvy.audi.service.GenericManager;
import org.compass.core.CompassHit;
import org.compass.core.support.search.CompassSearchCommand;
import org.compass.core.support.search.CompassSearchHelper;
import org.compass.core.support.search.CompassSearchResults;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * This class serves as the Base class for all other Managers - namely to hold
 * common CRUD methods that they might all use. You should only need to extend
 * this class when your require custom CRUD logic.
 * <p/>
 * <p>To register this class in your Spring context file, use the following XML.
 * <pre>
 *     &lt;bean id="userManager" class="com.ogilvy.audi.service.impl.GenericManagerImpl"&gt;
 *         &lt;constructor-arg&gt;
 *             &lt;bean class="com.ogilvy.audi.dao.hibernate.GenericDaoHibernate"&gt;
 *                 &lt;constructor-arg value="com.ogilvy.audi.model.User"/&gt;
 *                 &lt;property name="sessionFactory" ref="sessionFactory"/&gt;
 *             &lt;/bean&gt;
 *         &lt;/constructor-arg&gt;
 *     &lt;/bean&gt;
 * </pre>
 * <p/>
 * <p>If you're using iBATIS instead of Hibernate, use:
 * <pre>
 *     &lt;bean id="userManager" class="com.ogilvy.audi.service.impl.GenericManagerImpl"&gt;
 *         &lt;constructor-arg&gt;
 *             &lt;bean class="com.ogilvy.audi.dao.ibatis.GenericDaoiBatis"&gt;
 *                 &lt;constructor-arg value="com.ogilvy.audi.model.User"/&gt;
 *                 &lt;property name="dataSource" ref="dataSource"/&gt;
 *                 &lt;property name="sqlMapClient" ref="sqlMapClient"/&gt;
 *             &lt;/bean&gt;
 *         &lt;/constructor-arg&gt;
 *     &lt;/bean&gt;
 * </pre>
 *
 * @param <T>  a type variable
 * @param <PK> the primary key for that type
 * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
 */
public class GenericManagerImpl<T, PK extends Serializable> implements GenericManager<T, PK> {
    /**
     * Log variable for all child classes. Uses LogFactory.getLog(getClass()) from Commons Logging
     */
    protected final Log log = LogFactory.getLog(getClass());

    /**
     * GenericDao instance, set by constructor of child classes
     */
    protected GenericDao<T, PK> dao;

    @Autowired
    private CompassSearchHelper compass;

    public GenericManagerImpl() {
    }

    public GenericManagerImpl(GenericDao<T, PK> genericDao) {
        this.dao = genericDao;
    }

    /**
     * {@inheritDoc}
     */
    public List<T> getAll() {
        return dao.getAll();
    }

    /**
     * {@inheritDoc}
     */
    public T get(PK id) {
        return dao.get(id);
    }

    /**
     * {@inheritDoc}
     */
    public boolean exists(PK id) {
        return dao.exists(id);
    }

    /**
     * {@inheritDoc}
     */
    public T save(T object) {
        return dao.save(object);
    }

    /**
     * {@inheritDoc}
     */
    public void remove(PK id) {
        dao.remove(id);
    }

    /**
     * {@inheritDoc}
     * <p/>
     * Search implementation using Compass.
     */
    @SuppressWarnings("unchecked")
    public List<T> search(String q, Class clazz) {
        if (q == null || "".equals(q.trim())) {
            return getAll();
        }

        List<T> results = new ArrayList<T>();

        CompassSearchCommand command = new CompassSearchCommand(q);
        CompassSearchResults compassResults = compass.search(command);
        CompassHit[] hits = compassResults.getHits();

        if (log.isDebugEnabled() && clazz != null) {
            log.debug("Filtering by type: " + clazz.getName());
        }

        for (CompassHit hit : hits) {
            if (clazz != null) {
                if (hit.data().getClass().equals(clazz)) {
                    results.add((T) hit.data());
                }
            } else {
                results.add((T) hit.data());
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("Number of results for '" + q + "': " + results.size());
        }

        return results;
    }



    public List<T> getRecordsByCondition(int firstRecord, int page_size,  Map<String,Object> condition,String equals,String... paras) {

        String resultSql = getResultSql(condition,equals, paras);
           Collection dateSet=this.getDateSet(condition);
        if (log.isDebugEnabled()) {
            log.debug("resultSql is:" + resultSql);
        }

        String countSql = getCountSql(resultSql,paras);
        condition.put("resultsql", countSql);
        condition.put("dateSet", dateSet);
        resultSql= getSelectFields()+resultSql;

        return dao.getRecords(firstRecord,page_size,resultSql,dateSet);
    }

    /**
     * 拼装 查询HQL 语句
     * @param condition
     * @param equals
     * @param paras
     * @return
     */
    protected String getResultSql(Map condition,String equals,String... paras){
         String resultSql = "from " + getHQLKey() + " as r where 1=1 ";
         resultSql+=getSearchParaSql(condition,equals);
         resultSql+=getSearchDateSql(condition);
         resultSql+=getSearchSortSql(condition);
        return resultSql;
    }

    protected String getSelectFields(){
        return "";
    }

    /**
     * 统计 总记录数
     * @param resultSql
     * @param paras
     * @return
     */
    protected String getCountSql(String resultSql,String... paras){
          String countSql = "select count(*) " + resultSql;
        return countSql;
    }



    public List<T> getRecordsByHql(String hql, Collection dateSet) {
      return dao.getRecords(hql,dateSet);
    }

    public List<T> getRecordsByHql(String hql, int firstRecord, int page_size, Collection dateSet) {
        return dao.getRecords(firstRecord,page_size,hql,dateSet);  //To change body of implemented methods use File | Settings | File Templates.
    }





    /**
     *
     * @param condition
     * @param equals
     * @return
     */
    public List<T> getRecordsByCondition(Map<String, Object> condition,String equals) {
          log.debug("Entering getRecordsByCondition method ");
         String resultSql = "from " + getHQLKey() + " as r where 1=1 ";
          if(null==equals)
           equals="false";

//          Map paraMap=(Map)condition.get(PageConstants.DEFAULT_PARA_NAME);
//          Map sortMap=(Map)condition.get(PageConstants.DEFAULT_SORT_NAME);
//          Map dateMap=(Map)condition.get(PageConstants.DEFAULT_DATE_NAME);
         resultSql+=getSearchParaSql(condition,equals);
         resultSql+=getSearchDateSql(condition);
         resultSql+=getSearchSortSql(condition);
          Collection dateSet=this.getDateSet(condition);
        if (log.isDebugEnabled())
            log.debug("resultSql is:" + resultSql);
        return dao.getRecords(resultSql,dateSet);  //To change body of implemented methods use File | Settings | File Templates.
    }


   public Integer getRecordSizeBySql(String sql,Collection dateSet) {
        if (null == dao) {
            if (log.isDebugEnabled()) {
                log.debug("dao is null");
            }
            return Integer.valueOf(1);
        }
            Integer maxSize=1;
         if(sql.indexOf("group by")<0){
   //          log.debug("index of  count "+sql) ;
             maxSize = dao.getRecordSizeBySql(sql,dateSet);
         }else{
         //      log.debug(" not index of  count "+sql) ;
            maxSize = dao.getCountGroupSize(sql,dateSet);
         }

        if (log.isDebugEnabled()) {
            log.debug("in Manager record size is: " + maxSize);
        }

        return maxSize;
    }





    public Integer getRecordSizeBySql(Map<String, Object> condition,String equals) {
        if (null == dao) {
            if (log.isDebugEnabled()) {
                log.debug("dao is null");
            }

            return Integer.valueOf(1);
        }
         String resultSql = "select count(*) from " + getHQLKey() + " as r where 1=1 ";
          if(null==equals)
            equals="false";
//          Map paraMap=(Map)condition.get(PageConstants.DEFAULT_PARA_NAME);
//          Map sortMap=(Map)condition.get(PageConstants.DEFAULT_SORT_NAME);
//          Map dateMap=(Map)condition.get(PageConstants.DEFAULT_DATE_NAME);

         resultSql+=getSearchParaSql(condition,equals);
         resultSql+=getSearchDateSql(condition);
         resultSql+=getSearchSortSql(condition);
              Collection dateSet=this.getDateSet(condition);
        if (log.isDebugEnabled()) {
            log.debug("resultSql is:" + resultSql);
        }

        Integer maxSize = dao.getRecordSizeBySql(resultSql,dateSet);

        if (log.isDebugEnabled()) {
            log.debug("in Manager record size is: " + maxSize);
        }

        return maxSize;
    }
      public List<T> cacheGetRecordsByCondition( Map<String, Object> condition,String equals){
          return    getRecordsByCondition(condition,equals);
     }


     public String getHQLKey(){
       Class entityClass=(Class)((ParameterizedType) getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0];
        String name=entityClass.getSimpleName();
       //  log.debug("The name is "+name);
        return name;
    }



     /**
     * 参数搜索Hql
     * @param condition
     * @param equals    notNull: and field is not null
      *                            not:field != value  use:"!=" default "="
     * @return
     */
  protected String getSearchParaSql(Map condition,String equals){

           String paraHql="";
          List<PageParameter> pars=(List)condition.get(PageConstants.DEFAULT_PARA_NAME);
      paraHql =getHqlFromParList(pars,equals);
//           if(null==pars){
//               return paraHql;
//           }
//          for(PageParameter par:pars){
//                String parName=par.getParName();
//
//            if(StringUtils.isBlank(par.getParValue())&&StringUtils.isNotBlank(parName)){
//                 paraHql = paraHql + " and "+par.getAlias()+"." + parName + " is null" ;
//                 break;
//             }
//             if(par.getParValue().equals("notNull")){
//                 paraHql = paraHql + " and "+par.getAlias()+"." + parName + " is not null" ;
//                 break;
//             }
//
//
//              if(par.isFuzzyStatus())
//                paraHql = paraHql + " and "+par.getAlias()+"." + parName+ " like '%" + par.getParValue() +
//                    "%'";
//              else {
//                       String  determine="=" ;
//                        if(equals.equals("not")){
//                              determine="!=" ;
//                           }
//                          paraHql = paraHql + " and "+par.getAlias()+"." + parName+ determine +"'"+ par.getParValue() + "'";
//              }
//          }

         return  paraHql;
    }

   protected String getHqlFromParList(    List<PageParameter> pars,String equals){
        String paraHql="";
                if(null==pars){
               return paraHql;
           }
          for(PageParameter par:pars){
                String parName=par.getParName();

            if(StringUtils.isBlank(par.getParValue())&&StringUtils.isNotBlank(parName)){
                 paraHql = paraHql + " and "+par.getAlias()+"." + parName + " is null" ;
                 break;
             }
             if(par.getParValue().equals("notNull")){
                 paraHql = paraHql + " and "+par.getAlias()+"." + parName + " is not null" ;
                 break;
             }


              if(par.isFuzzyStatus())
                paraHql = paraHql + " and "+par.getAlias()+"." + parName+ " like '%" + par.getParValue() +
                    "%'";
              else {
                       String  determine="=" ;
                        if(equals.equals("not")){
                              determine="!=" ;
                           }
                          paraHql = paraHql + " and "+par.getAlias()+"." + parName+ determine +"'"+ par.getParValue() + "'";
              }
          }
       return paraHql;
   }



    /**
     * ����ʱ���ѯHQL
     * @param condition
     * @return
     */
       protected String getSearchDateSql(Map condition){

            String dateHql="";
       List<PageParameter> dates=(List)condition.get(PageConstants.DEFAULT_DATE_NAME);
           if(null==dates){
               return dateHql;
           }

          for(PageParameter parDate:dates){
              String name=parDate.getParName();

            dateHql = dateHql + " and "+parDate.getAlias()+"." + name + " "+parDate.getCompareSymbol()+"?";
          }


         log.debug("The searche dateHql sql is "+dateHql) ;
        return dateHql;
    }






    /**
     * 获得排序HQL 语句
     * @return
     */
     protected String getSearchSortSql(Map condition){
        String sortHql="";
        int ii=0;
        List<PageParameter> pars=(List)condition.get(PageConstants.DEFAULT_SORT_NAME);
           if(null==pars){
               return sortHql;
           }

           for(PageParameter parSort:pars){

             String key = parSort.getParName();
            String value=(String)parSort.getParValue();
             if(ii==0)
              sortHql+=" order by "+key+" "+value;
             else
              sortHql+=" "+key+" "+value;
              ii++;
           }

//        if(null==sortMap)
//            return sortHql;
//
//        Iterator i = sortMap.keySet().iterator();
//         while(i.hasNext()){
//
//            String key = (String) i.next();
//            String value=(String)sortMap.get(key);
//             if(ii==0)
//              sortHql+=" order by "+key+" "+value;
//             else
//              sortHql+=" "+key+" "+value;
//          ii++;
//         }
        return sortHql;
    }


  private Collection getDateSet(Map condition){
        List<String> dateSet=new ArrayList<String>();
       List<PageParameter> dates=(List)condition.get(PageConstants.DEFAULT_DATE_NAME);
           for(PageParameter parDate:dates){
              String cal=parDate.getParValue();
                dateSet.add(cal);
          }
           return dateSet;
    }
}
